package de.homelabs.moonrat.context;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javolution.util.FastList;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.stereotype.Service;

import de.homelabs.moonrat.MoonratBootstrap;
import de.homelabs.moonrat.config.MoonratConfigurationManager;
import de.homelabs.moonrat.exception.MoonratErrorCode;
import de.homelabs.moonrat.exception.MoonratException;

@Service
public class DataProviderService {
	static Logger logger = Logger.getLogger(DataProviderService.class);
	
	private Map<String, List<IDataProvider>> dataProviders = new HashMap<String, List<IDataProvider>>();
	
	@Autowired
	private MoonratConfigurationManager mRConfigManager;
	
	private ApplicationContext applicationContext;
	private AutowireCapableBeanFactory autoWireCapableBeanFactory;
	private GenericApplicationContext genericApplicationContext;
	
	public boolean registerDataProvider(String key, IDataProvider dataProvider){
		//test if key exists
		if (dataProviders.containsKey(key)){
			//add to list
			dataProviders.get(key).add(dataProvider);
		} else {
			//create new List
			List<IDataProvider> dpList = new ArrayList<IDataProvider>();
			//add provider
			dpList.add(dataProvider);
			//add list
			dataProviders.put(key, dpList);
		}
		//return
		return true;
	}

	public Map<String, List<IDataProvider>> getDataProviders() {
		return dataProviders;
	}

	public List<IDataProvider> getDataProviderByProviderKey(String key){
		if (dataProviders.containsKey(key)){
			return dataProviders.get(key);
		} else {
			logger.error("DataProvider for Key '"+key+"' not found!");
			return null;
		}
	}
	
	/**
	 * called from {@link MoonratBootstrap}
	 * 
	 * @param context
	 * @throws MoonratException
	 */
	public void initDataProvider(ApplicationContext context) throws MoonratException {
		//check 
		if (context == null) throw new MoonratException(MoonratErrorCode.INITIALIZATION_ERROR, " applicationContext missing");
		if (mRConfigManager == null || mRConfigManager.getConfig() == null || mRConfigManager.getConfig().getDataProvider() == null)
			throw new MoonratException(MoonratErrorCode.INITIALIZATION_ERROR, " config missig or no data providers found");
		
		//save application context
		this.applicationContext = context;
		this.autoWireCapableBeanFactory = applicationContext.getAutowireCapableBeanFactory();
		this.genericApplicationContext = new GenericApplicationContext(this.applicationContext);
		
		//get a list of data providers from config (FQBN)
		FastList<String> dataProvider = mRConfigManager.getConfig().getDataProvider();
		
		//register
		for (String providerClass : dataProvider){
			if (!providerClass.equalsIgnoreCase("")){
				try {
					//create a class
					Class<?> dynamicProviderClass = Class.forName(providerClass);
					
					//instance a bean with full autowiring
					Object dynamicBean = this.autoWireCapableBeanFactory.autowire(dynamicProviderClass, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);
					
					if (dynamicBean instanceof IDataProvider){
						//cast to data provider
						IDataProvider dpDynamicBean = (IDataProvider) dynamicBean;
						
						//add to spring context
						genericApplicationContext.getBeanFactory().registerSingleton(dpDynamicBean.getProviderName(), dpDynamicBean);
						
						//register to service
						registerDataProvider(dpDynamicBean.getProviderKey(), dpDynamicBean);
					} else {
						logger.error("Not a valid IDataProvider!");
					}
				} catch (ClassNotFoundException e){
					logger.error("Error initializing dataProvider: "+e.getMessage());
				}
			}
		}
	}
}
